<?php


namespace app\common\service;

use Wechat\WxPay;

//微信支付
class WxPayService
{
    const PAY_BANK = 'https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank';//企业付款到银行卡
    const TRANSFERS = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';//企业付款到零钱
    const REFUND = 'https://api.mch.weixin.qq.com/secapi/pay/refund';//退单
    const ORDERQUERY = 'https://api.mch.weixin.qq.com/pay/orderquery';//查询支付状态
    const UNIFIEDORDER = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

    /**
     * 企业付款到银行卡
     * @param $wx_config 微信配置
     * @param $bank 银行卡信息(bank_code:银行编号,bank_card_number：收款方银行卡号,realname：收款方用户名)
     * @param $order_info 订单信息(money:订单金额,desc:描述，order_sn:订单号)
     * @return bool|mixed|string
     * @throws \Exception
     */
    public static function payToBank($wx_config, $bank, $order_info)
    {
        if (empty($wx_config) || empty($bank) || empty($order_info)) {
            return false;
        }
        $config['appId'] = $wx_config['appId'];
        $config['appSecret'] = $wx_config['appSecret'];
        $config['mchid'] = $wx_config['mchid'];
        $config['pay_key'] = $wx_config['pay_key'];
        $config['url'] = self::PAY_BANK;
        $config['type'] = 3;
        $wxpay = new WxPay($config);
        if (DEBUG) {
            $order_info['money'] = 1;
        }
        $param = [
            'amount' => $order_info['money'],
            'bank_code' => $bank['bank_code'],
            'desc' => $order_info['desc'],
            'enc_bank_no' => $wxpay->RAS_openssl($bank['bank_card_number']),
            'enc_true_name' => $wxpay->RAS_openssl($bank['realname']),
            'mch_id' => $config['mchid'],
            'nonce_str' => $wxpay->createNoncestr(),
            'partner_trade_no' => $order_info['order_sn'],
        ];

        $param["sign"] = $wxpay->getSign($param);
        $xml = $wxpay->arrayToXml($param);
        $wxpay->url = $wxpay::PAY_BANK;
        $result = $wxpay->postXmlSSLCurl($xml, $wxpay->url);
        $result = $wxpay->xmlToArray($result);
        /*      if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
              } else {
              }*/
        return $result;

    }

    /**
     * 企业付款到零钱
     * @param $wx_config 微信配置
     * @param $openid 用户openid
     * @param $order_info 订单信息(money:订单金额,desc:描述，order_sn:订单号)
     * @return bool|mixed|string
     * @throws \Exception
     */
    public static function payToSmallChange($wx_config, $openid, $order_info)
    {

        if (empty($wx_config) || empty($openid) || empty($order_info)) {
            return false;
        }
        $config['appId'] = $wx_config['appId'];
        $config['appSecret'] = $wx_config['appSecret'];
        $config['mchid'] = $wx_config['mchid'];
        $config['pay_key'] = $wx_config['pay_key'];
        $config['url'] = self::TRANSFERS;
        $config['type'] = 2;
        $wxpay = new WxPay($config);
        $order['openid'] = $openid;
        $order['check_name'] = 'NO_CHECK';
        $order['amount'] = $order_info['money'];
        $order['desc'] = $order_info['desc'];
        $order['partner_trade_no'] = $order_info['order_sn'];
        $parameterArray = ['openid', 'check_name', 'amount', 'desc', 'partner_trade_no'];
        $wxpay->setParameter($order, $parameterArray);
        $result = $wxpay->postXmlSSL();
        $result = $wxpay->xmlToArray($result);
        return $result;
    }

    /**
     *   NATIVE支付
     * @param $wx_config 微信配置
     * @param $openid 用户openid
     * @param $order_info 订单信息(money:订单金额,order_sn:订单号)
     * @param $notify_url 回调地址
     * @param $payment_mode 支付方式1普通商户支付 2服务商支付
     * @return bool|mixed|string
     * @throws \Exception
     */
    public static function nativePay($wx_config, $order_info, $notify_url, $sub_mchid = '', $payment_mode = 1)
    {
        if ($payment_mode == 2) {//服务商支付
            return self::service_native_pay($wx_config, $order_info, $notify_url, $sub_mchid);
        } else {
            return self::common_native_pay($wx_config, $order_info, $notify_url);
        }
    }

    //普通商户支付
    public static function common_native_pay($wx_config, $order_info, $notify_url)
    {
        $wxpay = new WxPay($wx_config);
        $wxorder['appid'] = $wx_config['appId'];
        $wxorder['mch_id'] = $wx_config['mchid'];
        $wxorder['body'] = $wx_config['app_wx_name'];
        $wxorder['total_fee'] = $order_info['money'] * 100;
        $wxorder['spbill_create_ip'] = '0.0.0.0';
        $wxorder['notify_url'] = $notify_url; //微信回调地址; //微信回调地址
        $wxorder['trade_type'] = 'NATIVE';
        $wxorder['product_id'] = $order_info['order_id'];
        $wxorder['sign_type'] = "MD5";
        $wxorder['nonce_str'] = $wxpay->createNoncestr();
        $wxorder['out_trade_no'] = $order_info['order_sn'];
        $wxorder['sign'] = $wxpay->getSign($wxorder);
        $xml = $wxpay->arrayToXml($wxorder);
        $code = $wxpay->postXmlCurl($xml, self::UNIFIEDORDER);
        $result = $wxpay->xmlToArray($code);
        return $result;
    }

    /**
     * 服务商商户支付
     */
    public static function service_native_pay($wx_config, $order_info, $notify_url, $sub_mchid)
    {
        $wechat_config = config('api_dev.wechat');
        $wxpay = new WxPay($wechat_config);
        $wxorder['appid'] = $wechat_config['appId'];
        $wxorder['mch_id'] = $wechat_config['mchid'];
        $wxorder['body'] = $wx_config['app_wx_name'];
        $wxorder['total_fee'] = $order_info['money'] * 100;

        $wxorder['sub_mch_id'] = $sub_mchid;
        $wxorder['spbill_create_ip'] = '0.0.0.0';
        $wxorder['notify_url'] = $notify_url; //微信回调地址; //微信回调地址
        $wxorder['trade_type'] = 'NATIVE';
        $wxorder['product_id'] = $order_info['order_id'];
        $wxorder['sign_type'] = "MD5";
        $wxorder['nonce_str'] = $wxpay->createNoncestr();
        $wxorder['out_trade_no'] = $order_info['order_sn'];
        $wxorder['sign'] = $wxpay->getSign($wxorder);
        $xml = $wxpay->arrayToXml($wxorder);
        $code = $wxpay->postXmlCurl($xml, 'https://api.mch.weixin.qq.com/pay/unifiedorder');
        $code = $wxpay->xmlToArray($code);
        return $code;
    }


    /**
     *   JSAPI支付
     * @param $wx_config 微信配置
     * @param $openid 用户openid
     * @param $order_info 订单信息(money:订单金额,order_sn:订单号)
     * @param $notify_url 回调地址
     * @param $payment_mode 支付方式1普通商户支付 2服务商支付
     * @return bool|mixed|string
     * @throws \Exception
     */
    public static function pay($wx_config, $openid, $order_info, $notify_url, $sub_mchid = '', $payment_mode = 1)
    {
        if ($payment_mode == 2) {//服务商支付
            return self::service_pay($wx_config, $openid, $order_info, $notify_url, $sub_mchid);
        } else {
            return self::common_pay($wx_config, $openid, $order_info, $notify_url);
        }
    }

    //普通商户支付
    public static function common_pay($wx_config, $openid, $order_info, $notify_url)
    {
        $wxpay = new WxPay($wx_config);
        $order['openid'] = $openid;
        $order['spbill_create_ip'] = $order_info['spbill_create_ip'] ?? '';
        $order['body'] = empty($order_info['body']) ? $wx_config['app_wx_name'] : $order_info['body'];
        $order['out_trade_no'] = $order_info['order_sn'];//订单编号
        $order_money = $order_info['money'] * 100;

        $order['total_fee'] = $order_money;//订单金额
        $order['notify_url'] = $notify_url; //微信回调地址
        $order['trade_type'] = 'JSAPI';
        $order['attach'] = '1';
        $parameterArray = ['openid', 'body', 'out_trade_no', 'total_fee', 'notify_url', 'trade_type'];
        $wxpay->setParameter($order, $parameterArray);
        $timeStamp = time();
        $jsApiObj['appId'] = $wx_config['appId'];
        $jsApiObj["timeStamp"] = "$timeStamp";
        $jsApiObj["nonceStr"] = $wxpay->createNoncestr();
        $prepay_id = $wxpay->getPrepayId();
        $jsApiObj["package"] = "prepay_id=" . $prepay_id;
        $jsApiObj["signType"] = "MD5";
        $jsApiObj["paySign"] = $wxpay->getSign($jsApiObj);
        return $jsApiObj;
    }

    /**
     * 服务商商户支付
     */
    public static function service_pay($wx_config, $openid, $order_info, $notify_url, $sub_mchid)
    {
        $wechat_config = get_instance()->config->get('service_payment_config');
        $wechat_config['ip'] = $wx_config['ip'] ?? '0.0.0.0';
        $wxpay = new WxPay($wechat_config);

        $order['body'] = empty($order_info['body']) ? $wx_config['app_wx_name'] : $order_info['body'];
        $order['out_trade_no'] = $order_info['order_sn'];
        $order_money = $order_info['money'] * 100;

        $order['total_fee'] = $order_money;
        $order['notify_url'] = $notify_url; //微信回调地址
        $order['trade_type'] = 'JSAPI';
        $order['attach'] = '1';
        $order['sub_mch_id'] = $sub_mchid;
        $order['sub_appid'] = $wx_config['appId'];
        $order['sub_openid'] = $openid;
        $wxpay->setServiceParameter($order);
        $timeStamp = time();
        $jsApiObj['appId'] = $wx_config['appId'];
        $jsApiObj["timeStamp"] = "$timeStamp";
        $jsApiObj["nonceStr"] = $wxpay->createNoncestr();
        $prepay_id = $wxpay->getPrepayId();
        $jsApiObj["package"] = "prepay_id=" . $prepay_id;
        $jsApiObj["signType"] = "MD5";
        $jsApiObj["paySign"] = $wxpay->getSign($jsApiObj);
        return $jsApiObj;
    }


    /**
     * 微信退单
     * @param $wx_config 微信配置
     * @param $openid 用户openid
     * @param $order_info 订单信息(money:订单金额,order_sn:订单号)
     * @param $sub_mch_id 子商户号
     * @return bool|mixed|string
     * @throws \Exception
     */
    public static function wxRefund($wx_config, $order_info, $sub_mchid = '', $payment_mode = 1)
    {
        if ($payment_mode == 2) {//服务商支付
            return WxPayService::service_wxrefund($wx_config, $order_info, $sub_mchid);
        } else {
            return WxPayService::common_wxrefund($wx_config, $order_info);
        }
    }

    //普通商户退款
    public static function common_wxrefund($wx_config, $order_info)
    {
        $wxpay = new WxPay($wx_config);
        $url = self::REFUND; //接口连接
        $call_order_sn = $order_info['call_order_sn'];
        $total_fee = $order_info['total_fee'] * 100;
        $refund_fee = $order_info['refund_fee'] * 100;

        $order['transaction_id'] = $call_order_sn; //微信订单号
        $order['total_fee'] = $total_fee; //订单金额
        $order['refund_fee'] = $refund_fee; //退款金额
        $order['out_refund_no'] = $order_info['order_sn']; //商户退款单号
        $order['op_user_id'] = $wxpay->mchid; //操作员
        $order['appid'] = $wxpay->appid; //公众账号ID
        $order['mch_id'] = $wxpay->mchid; //商户号
        $order['nonce_str'] = $wxpay->createNoncestr(); //随机字符串
        $order['sign '] = $wxpay->getSign($order); //签名
        var_dump($order);
        $xml = $wxpay->arrayToXml($order); //数组装xml格式
        $res = $wxpay->postXmlSSLCurl($xml, $url); //提交
        $restObj = $wxpay->xmlToArray($res); //xml转数组
        return $restObj;
    }

    //服务商退款
    public static function service_wxrefund($wx_config, $order_info, $sub_mch_id)
    {

        $wechat_config = get_instance()->config->get('service_payment_config');
        $wechat_config['id'] = $wx_config['ip'];
        $wxpay = new WxPay($wechat_config);
        $url = self::REFUND; //接口连接
        $call_order_sn = $order_info['call_order_sn'];
        $total_fee = $order_info['total_fee'] * 100;
        $refund_fee = $order_info['refund_fee'] * 100;

        $order['transaction_id'] = $call_order_sn; //微信订单号
        $order['total_fee'] = $total_fee; //订单金额
        $order['refund_fee'] = $refund_fee; //退款金额
        $order['out_refund_no'] = $order_info['order_sn']; //商户退款单号
        $order['op_user_id'] = $wxpay->mchid; //操作员
        $order['appid'] = $wxpay->appid; //公众账号ID
        $order['mch_id'] = $wxpay->mchid; //商户号
        $order['sub_mch_id'] = $sub_mch_id;
        $order['nonce_str'] = $wxpay->createNoncestr(); //随机字符串
        $order['sign '] = $wxpay->getSign($order); //签名
        $xml = $wxpay->arrayToXml($order); //数组装xml格式
        $res = $wxpay->postXmlSSLCurl($xml, $url); //提交
        $restObj = $wxpay->xmlToArray($res); //xml转数组
        return $restObj;
    }

    /**
     * 查询支付状态
     * @param $wx_config 微信配置
     * @param $order_sn 订单号
     * @param $sub_mch_id 子商户号
     * @return bool|mixed|string
     * @throws \Exception
     */
    public static function queryPayStatus($wx_config, $order_sn, $sub_mch_id = '', $payment_mode = 1)
    {
        if ($payment_mode == 2) {//服务商
            return WxPayService::service_query_pay_status($wx_config, $order_sn, $sub_mch_id);
        } else {
            return WxPayService::common_query_pay_status($wx_config, $order_sn);
        }
    }

    //普通商户查询订单支付状态
    public static function common_query_pay_status($wx_config, $order_sn)
    {
        $wxpay = new WxPay($wx_config);
        $wxorder['appid'] = $wx_config['appId'];
        $wxorder['mch_id'] = $wx_config['mchid'];
        $wxorder['out_trade_no'] = $order_sn;
        $wxorder['nonce_str'] = $wxpay->createNoncestr();
        $wxorder['sign_type'] = 'MD5';
        $wxorder['sign'] = $wxpay->getSign($wxorder);
        $xml = $wxpay->arrayToXml($wxorder);
        $code = $wxpay->postXmlCurl($xml, self::ORDERQUERY);
        $code = $wxpay->xmlToArray($code);
        if ($code['return_code'] == 'SUCCESS' && $code['return_msg'] == 'OK' && isset($code['transaction_id']) && $code['trade_state_desc'] == '支付成功') {
            return returnResult(0, '支付成功', $code['return_code']);
        }
        return returnResult(1, $code['trade_state_desc']);
    }

    //服务商查询订单支付状态
    public static function service_query_pay_status($wx_config, $order_sn, $sub_mch_id)
    {
        $wechat_config = get_instance()->config->get('service_payment_config');
        $wechat_config['id'] = $wx_config['ip'];
        $wxpay = new WxPay($wechat_config);
        $wxorder['appid'] = $wx_config['appId'];
        $wxorder['mch_id'] = $wx_config['mchid'];
        $wxorder['sub_mch_id'] = $sub_mch_id;
        $wxorder['out_trade_no'] = $order_sn;
        $wxorder['nonce_str'] = $wxpay->createNoncestr();
        $wxorder['sign_type'] = 'MD5';
        $wxorder['sign'] = $wxpay->getSign($wxorder);
        $xml = $wxpay->arrayToXml($wxorder);
        $code = $wxpay->postXmlCurl($xml, self::ORDERQUERY);
        $code = $wxpay->xmlToArray($code);
        if ($code['return_code'] == 'SUCCESS' && $code['return_msg'] == 'OK' && isset($code['transaction_id']) && $code['trade_state_desc'] == '支付成功') {
            return returnResult(0, '支付成功', $code['return_code']);
        }
        return returnResult(-1, $code['trade_state_desc']);
    }

    public static function arrayToXml($arr)
    {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";

        return $xml;
    }

}
